package com.sandyz.virtualcam.hooks

import android.content.res.XModuleResources
import android.graphics.SurfaceTexture
import android.hardware.Camera
import android.hardware.camera2.CameraCaptureSession
import android.hardware.camera2.CameraDevice
import android.hardware.camera2.CaptureRequest
import android.hardware.camera2.params.InputConfiguration
import android.hardware.camera2.params.OutputConfiguration
import android.hardware.camera2.params.SessionConfiguration
import android.opengl.GLSurfaceView
import android.os.Build
import android.os.Handler
import android.view.Surface
import android.view.View
import android.view.ViewGroup
import androidx.core.view.children
import com.sandyz.virtualcam.utils.HookUtils
import com.sandyz.virtualcam.utils.PlayIjk
import com.sandyz.virtualcam.utils.xLog
import de.robv.android.xposed.XC_MethodHook
import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.XposedHelpers
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam
import tv.danmaku.ijk.media.player.IjkMediaPlayer

/**
 * WhatsApp虚拟摄像头实现
 * 
 * 主要功能：
 * 1. 视频流注入
 * 2. 相机预览拦截
 * 3. Surface管理
 * 4. 播放器控制
 * 
 * 实现细节：
 * - 支持WhatsApp应用
 * - 使用ijkplayer播放视频
 * - Camera2 API支持
 * - Surface重定向
 * 
 * @author sandyz987
 * @date 2024/9/18
 */
class VirtualCameraWs : IHook {
    // 1. 基本信息
    override fun getName(): String = "WhatsApp可用的虚拟摄像头模块"
    override fun getSupportedPackages() = listOf(
        "com.whatsapp",  // WhatsApp
    )

    // 2. 初始化
    override fun init(cl: ClassLoader?) {
    }

    override fun registerRes(moduleRes: XModuleResources?) {
    }

    // 3. Surface管理
    private var nullSurface: Surface? = null  // 空Surface
    private var nullSurfaceTex: SurfaceTexture? = null  // 空Surface纹理
    private var virtualSurface: Surface? = null  // 虚拟预览Surface

    // 4. 播放器管理
    private var ijkMediaPlayer: IjkMediaPlayer? = null  // 播放器实例
    // 要用class来hook接口，因为接口不能直接hook
    // 这些callback类设置为全局变量的原因是，如果为null就执行，确保只执行一次（防止多次hook同一个方法）
    //    private var deviceStateCallbackClazz: Class<*>? = null
    private var sessionStateCallbackClazz: Class<*>? = null  // 会话状态回调类

    /**
     * 4.1 创建播放器
     * 
     * @return IjkMediaPlayer 播放器实例
     */
    private fun newIjkMediaPlayer(): IjkMediaPlayer = IjkMediaPlayer {} // 已经加载库了就不加载了

    /**
     * 4.2 重置播放器
     * 
     * 处理流程：
     * 4.2.1 停止播放
     * 4.2.2 释放资源
     * 4.2.3 创建新实例
     */
    private fun resetIjkMediaPlayer() {
        if (ijkMediaPlayer?.isPlaying == true) {
            ijkMediaPlayer?.stop()
        }
        ijkMediaPlayer?.release()
        ijkMediaPlayer = newIjkMediaPlayer()
    }

    /**
     * 4.3 重置Surface
     * 
     * 处理流程：
     * 4.3.1 释放旧Surface
     * 4.3.2 创建新Surface
     */
    private fun resetSurface() {
        xLog("重置surface")
        virtualSurface = null
        nullSurfaceTex?.release()
        nullSurface?.release()
        nullSurfaceTex = SurfaceTexture(15)
        nullSurface = Surface(nullSurfaceTex)
    }

    /**
     * 5. Hook实现
     * 
     * 处理流程：
     * 5.1 Hook图片读取器
     * 5.2 Hook相机会话创建
     * 5.3 Hook相机输出目标
     * 5.4 Hook预览控制
     * 5.5 Hook相机请求构建
     */
    override fun hook(lpparam: LoadPackageParam?) {
        // 5.0 检查应用包名，只对支持的应用进行hook
        val packageName = lpparam?.packageName
        if (packageName !in getSupportedPackages()) {
            xLog("应用 $packageName 不在支持列表中，跳过hook")
            return
        }
        xLog("开始hook应用: $packageName")
        // 5.1 Hook图片读取器创建
        XposedHelpers.findAndHookMethod(
            "android.media.ImageReader", lpparam!!.classLoader, "newInstance",
            Int::class.javaPrimitiveType,
            Int::class.javaPrimitiveType,
            Int::class.javaPrimitiveType,
            Int::class.javaPrimitiveType, object : XC_MethodHook() {
                override fun beforeHookedMethod(param: MethodHookParam?) {
                    xLog("创建图片读取器ImageReader.newInstance   宽：${param?.args?.get(0)}，高：${param?.args?.get(1)}，格式：${param?.args?.get(2)}")
                }
            })

        // 5.2 Hook相机会话创建（Android 9及以上）
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            XposedHelpers.findAndHookMethod("android.hardware.camera2.impl.CameraDeviceImpl", lpparam.classLoader, "createCaptureSession", List::class.java, CameraCaptureSession.StateCallback::class.java, Handler::class.java, object : XC_MethodHook() {
                override fun beforeHookedMethod(param: MethodHookParam) {
                    xLog("whatsapp hook createCaptureSession")

                    val surfaceList = param.args[0] as List<Surface>
                    xLog("whatsapp hook createCaptureSession应用程序创建相机管道?   ")

                    // 替换为空的Surface列表
                    val newSurface = mutableListOf<Surface?>().apply { add(nullSurface) }
                    xLog("应用程序想要添加surfaces: $surfaceList，拦截后只添加：$nullSurface")
                    param.args[0] = newSurface
                }
            })
        }

        // 5.3 Hook相机输出目标
        XposedHelpers.findAndHookMethod("android.hardware.camera2.CaptureRequest.Builder", lpparam.classLoader, "addTarget", Surface::class.java, object : XC_MethodHook() {
            override fun beforeHookedMethod(param: MethodHookParam?) {
                xLog("应用程序向相机添加输出目标addTarget          surface: ${param?.args?.get(0)}")
                xLog("找到屏幕上的surface          surface: ${param?.args?.get(0)}")
                if (virtualSurface == null) { // 首次获取到屏幕Surface
                    resetSurface()
                    // 记录屏幕Surface用于播放器输出
                    virtualSurface = param?.args?.get(0) as Surface?
                    resetIjkMediaPlayer()
                    PlayIjk.play(virtualSurface, ijkMediaPlayer)
                }
                // 重定向相机输出到空Surface
                param?.args?.set(0, nullSurface)
            }
        })

        // 5.4 Hook预览控制
        XposedHelpers.findAndHookMethod("android.hardware.Camera", lpparam.classLoader, "startPreview", object : XC_MethodHook() {
            override fun beforeHookedMethod(param: MethodHookParam?) {
                xLog("应用程序开始预览startPreview         屏幕surface: $virtualSurface")
            }
        })

        // 5.5 Hook相机请求构建
        XposedHelpers.findAndHookMethod("android.hardware.camera2.CaptureRequest.Builder", lpparam.classLoader, "build", object : XC_MethodHook() {
            override fun beforeHookedMethod(param: MethodHookParam?) {
                xLog("应用程序相机请求创建CaptureRequest.Build         屏幕surface: $virtualSurface       ijkm: $ijkMediaPlayer")
                val builder = (param?.thisObject as? CaptureRequest.Builder)
                // 获取Surface集合
                val request = XposedHelpers.getObjectField(builder, "mRequest") as CaptureRequest
                val surfaceSet = XposedHelpers.getObjectField(request, "mSurfaceSet") as MutableSet<*>
                xLog("surfaceSet: $surfaceSet")
            }
        })

        // 5.6 Hook TextureView创建
        val clazz = XposedHelpers.findClass("android.view.TextureView", lpparam.classLoader)
        xLog("TextureView: $clazz")
        XposedBridge.hookAllConstructors(clazz, object : XC_MethodHook() {
            override fun afterHookedMethod(param: MethodHookParam?) {
                xLog("TextureView: ${param?.thisObject}")
            }
        })
    }
}